import guid from '@/libs/guid.js'
import { fabric } from 'fabric'
import saveAs from '@/libs/FileSaver.js'
import Element from './Element.js'
import FlowGroup from './FlowGroup.js'
import EventEmitter from './EventEmitter.class.js'
import { reactive } from 'vue'
import Panel from './Panel.js'
import Basic from './Basic.js'
export function createCanvasComponent(options) {
  return new CanvasComponent(options)
}

class CanvasComponent extends Basic {
  constructor(options) {
    super(options)
    this.canvas = options.component
    //this.background = new fabric.Rect({
    //fill: '#fff',
    //width: this.canvas.width,
    //height: this.canvas.height,
    //selectable: false
    //})
    //this.canvas.add(this.background)
    this.options = options
    this.context = options.context
    this.canvas.on('selection:updated', (e) => {
      console.log('selection:updated', e)
      let item = this.find(e.target.guid)
      this.onSelection(item)
    })
    this.canvas.on('selection:created', (e) => {
      console.log('selection:created', e)
      let item = this.find(e.target.guid)
      this.onSelection(item)
    })
    this.canvas.on('selection:cleared', (e) => {
      this.onSelection()
    })
    this.canvas.on('mouse:wheel', (opt) => {
      //let { offsetX, offsetY } = opt.e
      let canvas = this.canvas
      var delta = opt.e.deltaY
      var zoom = canvas.getZoom()
      zoom *= 0.999 ** delta
      if (zoom > 20) zoom = 20
      if (zoom < 0.01) zoom = 0.01
      //canvas.setZoom(zoom)
      canvas.zoomToPoint(new fabric.Point(canvas.width / 2, canvas.height / 5), zoom)
      //console.log(canvas.viewportTransform)
      opt.e.preventDefault()
      opt.e.stopPropagation()
    })
    this.canvas.set({
      backgroundColor: '#FFFFFF'
    })

    this.on('move', () => {
      this.refresh()
    })
  }
  resetZoom() {
    this.canvas.zoomToPoint(new fabric.Point(this.canvas.width / 2, this.canvas.height / 5), 1)
  }
  setWidth(w) {
    this.canvas.setWidth(w)
    //this.background.set({
    //width: parseInt(w)
    //})
  }
  setHeight(h) {
    this.canvas.setHeight(h)
    //this.background.set({
    //height: parseInt(h)
    //})
  }
  add(item, options) {
    let elem
    if (item.type == 'group') {
      console.log(item, 'group')
      elem = FlowGroup.fromCanvas({
        component: item,
        canvas: this.canvas,
        ...options
      })
    } else {
      elem = new Element({
        component: item,
        ...options
      })
    }

    return this.addElem(elem)
  }
  addElem(elem) {
    super.add(elem)
    this.canvas.renderAll()
    this.emit('update')
    return elem
  }
  createGroup() {
    let group = new FlowGroup({
      canvas: this.canvas
    })
    this.addElem(group)
  }
  onSelection(target) {
    const { onSelection } = this.options
    if (!target) {
      onSelection()
    } else {
      onSelection(target)
    }
  }
  find(guid) {
    return this.list.find((res) => res.guid == guid)
  }
  noAct() {
    this.canvas.discardActiveObject()
    this.canvas.renderAll()
  }
  output() {
    let json = this.toJSON()
    console.log(json)
    let content = JSON.stringify(json)
    var blob = new Blob([content], { type: 'text/plain;charset=utf-8' })
    let fileName = 'ouput_bk.json'
    saveAs(blob, fileName)
  }
  outputElement2() {
    let json = this.toJSON()
    console.log(`json`, json)
    let { width: w, height: h } = json
    let root = {
      type: 'rect',
      w,
      h,
      childs: json.objects.map((res, index) => {
        return this.deepOutput(res, index)
      })
    }
    let content = JSON.stringify(root)
    var blob = new Blob([content], { type: 'text/plain;charset=utf-8' })
    let fileName = 'ouput_zrender.json'
    saveAs(blob, fileName)
    console.log(root)
    return root
  }
  deepOutput(res, index) {
    let obj = {}
    switch (res.type) {
      case 'text':
        let lines = Math.round(res.height / res.fontSize)
        let lineHeight = res.height / lines
        obj = {
          type: 'text',
          mode: 0,
          w: res.width,
          h: res.height,
          position: [res.left, res.top],
          css: {
            text: res.text,
            background: res.fill,
            font: `${res.fontWeight} ${res.fontSize}px ${res.fontFamily}`,
            textWidth: res.width
          }
        }
        break
      case 'group':
        obj = {
          type: 'space',
          mode: 0,
          w: res.width,
          h: res.height,
          position: [res.left, res.top],
          childs: res.objects.map((child) => {
            //这里统一修正成右上角
            child.left = child.left + res.width / 2
            child.top = child.top + res.height / 2
            return this.deepOutput(child, index)
          })
        }
        break
      case 'image':
        obj = {
          type: 'image',
          mode: 0,
          w: res.width,
          h: res.height,
          position: [res.left, res.top],
          url: res.src
        }
        break
      default:
        obj = {
          type: 'rect',
          mode: 0,
          w: res.width,
          h: res.height,
          position: [res.left, res.top],
          css: {
            background: res.fill
          }
        }
        break
    }
    obj.ext = Object.assign({}, obj.ext, {
      scale: [res.scaleX, res.scaleY],
      z: res.z,
      rotation: -(res.angle / 180) * Math.PI
    })
    obj.config = res.config
    //obj.fabric = res
    return obj
  }
  input(json) {
    if (json.height) this.canvas.setHeight(json.height)
    if (json.width) this.canvas.setWidth(json.width)
    if (json.viewportTransform) this.canvas.setViewportTransform(json.viewportTransform)
    this.canvas.loadFromJSON(json, () => {
      let objects = this.canvas.getObjects()
      this.canvas.clear()
      this.list.length = 0
      objects.forEach((res) => {
        this.add(res)
      })
    })
  }
  inputByFile(file) {
    return new Promise((resolve) => {
      let fr = new FileReader()
      fr.readAsText(file)
      fr.onload = (e) => {
        let json = JSON.parse(e.target.result)
        this.input(json)
        resolve(json)
      }
    })
  }
  createImgByFile(file, stage) {
    let fr = new FileReader()
    fr.readAsDataURL(file)
    fr.onload = (e) => {
      let img = new Image()
      img.src = e.target.result
      img.onload = (e) => {
        console.log(e.target.width, e.target.height)
        let ow = e.target.width
        let oh = e.target.height
        let { width: sw, height: sh } = stage

        let radio = ow / oh
        let w_rate = ow / sw
        let h_rate = oh / sh

        let e_rate = 1
        if (w_rate > h_rate && w_rate > 1) {
          e_rate = 1 / w_rate
        }
        if (h_rate > w_rate && h_rate > 1) {
          e_rate = 1 / h_rate
        }

        console.log(ow, oh, e_rate)

        var fimg = new fabric.Image(img, {
          left: 0,
          top: 0,
          width: ow,
          height: oh,
          scaleX: e_rate,
          scaleY: e_rate
        })
        let element = this.add(fimg)
        element.select()
      }
    }
  }
  toJSON() {
    let json = {}
    const { width, height, viewportTransform } = this.canvas
    json.width = width
    json.height = height
    json.viewportTransform = viewportTransform
    let levels = this.getLevels()

    const toJSON = (root) => {
      let objects = root
        .map((res) => {
          let json = res.component.toJSON()
          let guid = res.guid
          let level = levels[guid]
          json.z = level.z
          json.config = res.config
          if (res.list) {
            json.objects = toJSON(res.list)
          } else {
            json.objects = []
          }
          return json
        })
        .sort((a, b) => {
          return a.z - b.z
        })
      return objects
    }

    let objects = toJSON(this.list)
    json.objects = objects
    return json
  }
  getLevels() {
    let obj = this.canvas.toObject(['guid'])
    let levelArr = {}
    const deepLevel = (objects, parentLevel = []) => {
      objects.forEach((res, i) => {
        let pl = Object.assign([], parentLevel)
        pl.push(i)
        if (res.objects && res.objects.length) {
          deepLevel(res.objects, pl)
        }
        let z = 0
        for (var p = 0; p < pl.length; p++) {
          z = z + pl[p] * Math.pow(0.01, p)
        }
        levelArr[res.guid] = {
          z: z,
          level: pl
        }
      })
    }
    deepLevel(obj.objects)
    return levelArr
  }
  scaleImgFit(src, stage) {
    scaleImgFit(src, stage)
  }
  refresh() {
    this.canvas.renderAll()
  }
}

export function scaleImgFit(src, stage) {
  return new Promise((resolve) => {
    let img = new Image()
    img.src = src
    img.onload = (e) => {
      console.log(e.target.width, e.target.height)
      let ow = e.target.width
      let oh = e.target.height
      let { width: sw, height: sh } = stage
      let radio = ow / oh
      let w_rate = ow / sw
      let h_rate = oh / sh
      let e_rate = 1
      if (w_rate > h_rate && w_rate > 1) {
        e_rate = 1 / w_rate
      }
      if (h_rate > w_rate && h_rate > 1) {
        e_rate = 1 / h_rate
      }
      resolve({
        src: src,
        img,
        width: ow,
        height: oh,
        scaleX: e_rate,
        scaleY: e_rate
      })
    }
  })
}
export { FlowGroup, Element }
